using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;

namespace ICSharpCode.TextEditor.Document
{
    public class XmlFoldingStrategy : IFoldingStrategy
    {
        private bool showAttributesWhenFolded = false;

        public List<FoldMarker> GenerateFoldMarkers(IDocument document, string fileName, object parseInformation)
        {
            return GenerateFoldMarkers(document);
        }

        public List<FoldMarker> GenerateFoldMarkers(IDocument document)
        {
            showAttributesWhenFolded = true;
            List<FoldMarker> list = new List<FoldMarker>();
            Stack stack = new Stack();
            try
            {
                string textContent = document.TextContent;
                XmlTextReader xmlTextReader = new XmlTextReader(new StringReader(textContent));
                xmlTextReader.DtdProcessing = DtdProcessing.Ignore;
                while (xmlTextReader.Read())
                {
                    switch (xmlTextReader.NodeType)
                    {
                        case XmlNodeType.Element:
                            if (!xmlTextReader.IsEmptyElement)
                            {
                                XmlFoldStart obj = CreateElementFoldStart(xmlTextReader);
                                stack.Push(obj);
                            }
                            break;
                        case XmlNodeType.EndElement:
                            {
                                XmlFoldStart foldStart = (XmlFoldStart)stack.Pop();
                                CreateElementFold(document, list, xmlTextReader, foldStart);
                                break;
                            }
                        case XmlNodeType.Comment:
                            CreateCommentFold(document, list, xmlTextReader);
                            break;
                    }
                }
            }
            catch (Exception)
            {
                return new List<FoldMarker>(document.FoldingManager.FoldMarker);
            }
            return list;
        }

        private void CreateCommentFold(IDocument document, List<FoldMarker> foldMarkers, XmlTextReader reader)
        {
            checked
            {
                if (reader.Value != null)
                {
                    string text = reader.Value.Replace("\r\n", "\n");
                    string[] array = text.Split('\n');
                    if (array.Length > 1)
                    {
                        int num = reader.LinePosition - 5;
                        int num2 = reader.LineNumber - 1;
                        int endColumn = array[array.Length - 1].Length + num + 3;
                        int endLine = num2 + array.Length - 1;
                        string foldText = "<!--" + array[0] + "-->";
                        FoldMarker item = new FoldMarker(document, num2, num, endLine, endColumn, FoldType.TypeBody, foldText);
                        foldMarkers.Add(item);
                    }
                }
            }
        }

        private XmlFoldStart CreateElementFoldStart(XmlTextReader reader)
        {
            XmlFoldStart xmlFoldStart = checked(new XmlFoldStart(reader.Prefix, reader.LocalName, reader.LineNumber - 1, reader.LinePosition - 2));
            if (showAttributesWhenFolded && reader.HasAttributes)
            {
                xmlFoldStart.FoldText = "<" + xmlFoldStart.Name + " " + GetAttributeFoldText(reader) + ">";
            }
            else
            {
                xmlFoldStart.FoldText = "<" + xmlFoldStart.Name + ">";
            }
            return xmlFoldStart;
        }

        private void CreateElementFold(IDocument document, List<FoldMarker> foldMarkers, XmlTextReader reader, XmlFoldStart foldStart)
        {
            checked
            {
                int num = reader.LineNumber - 1;
                if (num > foldStart.Line)
                {
                    int endColumn = reader.LinePosition + foldStart.Name.Length;
                    FoldMarker item = new FoldMarker(document, foldStart.Line, foldStart.Column, num, endColumn, FoldType.TypeBody, foldStart.FoldText);
                    foldMarkers.Add(item);
                }
            }
        }

        private string GetAttributeFoldText(XmlTextReader reader)
        {
            StringBuilder stringBuilder = new StringBuilder();
            checked
            {
                for (int i = 0; i < reader.AttributeCount; i++)
                {
                    reader.MoveToAttribute(i);
                    stringBuilder.Append(reader.Name);
                    stringBuilder.Append("=");
                    stringBuilder.Append(reader.QuoteChar.ToString());
                    stringBuilder.Append(XmlEncodeAttributeValue(reader.Value, reader.QuoteChar));
                    stringBuilder.Append(reader.QuoteChar.ToString());
                    if (i < reader.AttributeCount - 1)
                    {
                        stringBuilder.Append(" ");
                    }
                }
                return stringBuilder.ToString();
            }
        }

        private static string XmlEncodeAttributeValue(string attributeValue, char quoteChar)
        {
            StringBuilder stringBuilder = new StringBuilder(attributeValue);
            stringBuilder.Replace("&", "&amp;");
            stringBuilder.Replace("<", "&lt;");
            stringBuilder.Replace(">", "&gt;");
            if (quoteChar == '"')
            {
                stringBuilder.Replace("\"", "&quot;");
            }
            else
            {
                stringBuilder.Replace("'", "&apos;");
            }
            return stringBuilder.ToString();
        }
    }
}
